package org.seedframework.sharding.resource;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.tomlj.Toml;
import org.tomlj.TomlParseResult;
import org.tomlj.TomlTable;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;


/**
 * Scatter data source location properties
 */
@Slf4j
public class DataSourceProperties {

    private String clusterName;

    private String driverClassName;

    private List<DatabaseConnection> scatters;

    private Map<String, Set<DatabaseConnection>> doubleWrites;

    public DataSourceProperties(InputStream inputStream) {
        try {
            TomlParseResult result = Toml.parse(inputStream);
            this.clusterName = result.getString("clusterName");
            this.driverClassName = result.getString("driverClassName");
            this.scatters = new ArrayList<>();
            TomlTable tomlTable = result.getTableOrEmpty("scatters");
            if (!tomlTable.isEmpty()) {
                Set<String> keys = tomlTable.dottedKeySet(true);
                Assert.notEmpty(keys, "Database connection configs can not be empty.");
                keys.forEach(o -> {
                    if (tomlTable.isTable(o)) {
                        TomlTable connTable = tomlTable.getTable(o);
                        DatabaseConnection connection = new DatabaseConnection();
                        connection.setId(o);
                        connection.setPassword(connTable.getString("password"));
                        connection.setUsername(connTable.getString("username"));
                        connection.setUrl(connTable.getString("url"));
                        scatters.add(connection);
                    }
                });
            }

            // load double-write datasource
            TomlTable doubleWrites = result.getTableOrEmpty("double-writes");
            if (doubleWrites.isEmpty()) {
                return;
            }
            Set<String> keys = doubleWrites.dottedKeySet(true);

            this.doubleWrites = new HashMap<>();
            keys.forEach(o -> {
                if (doubleWrites.isTable(o)) {
                    TomlTable connTable = doubleWrites.getTableOrEmpty(o);
                    if (connTable.isEmpty()) {
                        return;
                    }
                    Set<String> connKeys = connTable.dottedKeySet(true);
                    connKeys.forEach(p -> {
                        if (connTable.isTable(p)) {
                            TomlTable pTable = connTable.getTable(p);
                            DatabaseConnection connection = new DatabaseConnection();
                            connection.setId(o + "." + p);
                            connection.setPassword(pTable.getString("password"));
                            connection.setUsername(pTable.getString("username"));
                            connection.setUrl(pTable.getString("url"));
                            Set<DatabaseConnection> set = this.doubleWrites.get(o);
                            if (set == null) {
                                set = new HashSet<>();
                            }
                            set.add(connection);
                            this.doubleWrites.put(o, set);
                        }
                    });
                }
            });

        } catch (IOException e) {
            e.printStackTrace();
        }

        log.info("Scatter configuration loaded: {}", new Gson().toJson(this));

    }


    public String getClusterName() {
        return clusterName;
    }

    public void setClusterName(String clusterName) {
        this.clusterName = clusterName;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public List<DatabaseConnection> getScatters() {
        return scatters;
    }

    public void setScatters(List<DatabaseConnection> scatters) {
        this.scatters = scatters;
    }

    public Map<String, Set<DatabaseConnection>> getDoubleWrites() {
        return doubleWrites;
    }

    public void setDoubleWrites(Map<String, Set<DatabaseConnection>> doubleWrites) {
        this.doubleWrites = doubleWrites;
    }

    /**
     * Database connection parameters
     */
    public static class DatabaseConnection {

        private String id;

        private String url;

        private String username;

        private String password;


        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

    }


}
